#ifndef PATTERN_H
#define PATTERN_H

#include "matcher.h"
#include <cstring>
#include <vector>
#include <map>
#include <stdexcept>
class Node;
class CharClass;
class PatternSyntaxError :public std::logic_error{
public:
    PatternSyntaxError(const std::string& msg)
        :logic_error(msg){}
};

class UnsupportedEscape : public PatternSyntaxError{
public:
    UnsupportedEscape(const std::string& msg)
        :PatternSyntaxError(msg){}
};

class GroupNameConflict : public PatternSyntaxError{
public:
    GroupNameConflict(const std::string& msg)
        :PatternSyntaxError(msg){}
};

class Pattern
{
public:    
    Pattern(const char* _pattern,int _flags=0);
    ~Pattern();

    enum Flags{
        MULTILINE=1,
        IGNORECASE=2,
        DOTALL=4
    };
    int hasFlag(int flag){
        return (flags & flag);
    }    

    void compile();
    Matcher* match(const std::string& text);
    Matcher* search(const std::string& text,size_t from=0);

    Node* getAcceptNode() { return accept_node; }
    void addChild(Node* child){
        child_nodes.push_back(child);
    }

    int getIndexedGroupCount(){
        return capture_group_count;
    }
    void addName(const std::string& name,int index){
        group_name_map[name] = index;
    }

    int getIndexByName(const std::string& name){
        std::map<std::string,int>::iterator it = group_name_map.find(name);
        if(it==group_name_map.end())
            throw GroupNotExist(name);
        else
            return it->second;
    }

private:
    int     flags;
    const   char* pattern;
    size_t  pattern_len;
    Node*   root;
    Node*   accept_node;

    Node*      build();
    Node*      readAlternation();
    Node*      readGroup();
    CharClass* readCharClass(bool consume=true);
    int        readEscape(Node** node_ref);
    Node*      closure(Node*);

    int capture_group_count;
    std::map<std::string,int> group_name_map;

    size_t i;
    char peek(){ return pattern[i];}
    char next(){ return pattern[i++];}
    void unread(){--i;}
    void skip(){ ++i;}
    bool atEnd(){ return i>=pattern_len; }

    //memory manage
    std::vector<Node*> child_nodes;
};



#endif // PATTERN_H
